' Stephen Toub


Imports Microsoft.VisualBasic
Imports System
Imports System.IO
Imports System.Runtime.InteropServices.ComTypes

Namespace C4F.DevKit.PreviewHandler.PreviewHandlerFramework
    Public MustInherit Class StreamBasedPreviewHandler
        Inherits PreviewHandler
        Implements IInitializeWithStream
        Private _stream As IStream

        Private Sub IInitializeWithStream_Initialize(ByVal pstream As IStream, ByVal grfMode As UInteger) Implements IInitializeWithStream.Initialize
            _stream = pstream
        End Sub

        Protected Overrides Sub Load(ByVal c As PreviewHandlerControl)
            c.Load(New ReadOnlyIStreamStream(_stream))
        End Sub

        Private Class ReadOnlyIStreamStream
            Inherits Stream
            Private _stream As IStream

            Public Sub New(ByVal stream As IStream)
                If stream Is Nothing Then
                    Throw New ArgumentNullException("stream")
                End If
                _stream = stream
            End Sub

            Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
                _stream = Nothing
                MyBase.Dispose(disposing)
            End Sub

            Private Sub ThrowIfDisposed()
                If _stream Is Nothing Then
                    Throw New ObjectDisposedException(Me.GetType().Name)
                End If
            End Sub

            Public Overrides Function Read(ByVal buffer As Byte(), ByVal offset As Integer, ByVal count As Integer) As Integer
                ThrowIfDisposed()

                If buffer Is Nothing Then
                    Throw New ArgumentNullException("buffer")
                End If
                If offset < 0 Then
                    Throw New ArgumentNullException("offset")
                End If
                If count < 0 Then
                    Throw New ArgumentNullException("count")
                End If

                Dim bytesRead As Integer = 0
                If count > 0 Then
                    Dim ptr As IntPtr = New IntPtr(bytesRead)
                    If offset = 0 Then
                        If count > buffer.Length Then
                            Throw New ArgumentOutOfRangeException("count")
                        End If
                        _stream.Read(buffer, count, ptr)
                    Else
                        Dim tempBuffer As Byte() = New Byte(count - 1) {}
                        _stream.Read(tempBuffer, count, ptr)
                        If bytesRead > 0 Then
                            Array.Copy(tempBuffer, 0, buffer, offset, bytesRead)
                        End If
                    End If
                End If
                Return bytesRead
            End Function

            Public Overrides ReadOnly Property CanRead() As Boolean
                Get
                    Return Not _stream Is Nothing
                End Get
            End Property
            Public Overrides ReadOnly Property CanSeek() As Boolean
                Get
                    Return Not _stream Is Nothing
                End Get
            End Property
            Public Overrides ReadOnly Property CanWrite() As Boolean
                Get
                    Return False
                End Get
            End Property

            Public Overrides ReadOnly Property Length() As Long
                Get
                    ThrowIfDisposed()
                    Const STATFLAG_NONAME As Integer = 1
                    Dim stats As STATSTG
                    _stream.Stat(stats, STATFLAG_NONAME)
                    Return stats.cbSize
                End Get
            End Property

            Public Overrides Property Position() As Long
                Get
                    ThrowIfDisposed()
                    Return Seek(0, SeekOrigin.Current)
                End Get
                Set(ByVal value As Long)
                    ThrowIfDisposed()
                    Seek(value, SeekOrigin.Begin)
                End Set
            End Property

            Public Overrides Function Seek(ByVal offset As Long, ByVal origin As SeekOrigin) As Long
                ThrowIfDisposed()
                Dim pos As Long = 0
                Dim posPtr As IntPtr = New IntPtr(pos)
                _stream.Seek(offset, CInt(Fix(origin)), posPtr)
                Return pos
            End Function

            Public Overrides Sub Flush()
                ThrowIfDisposed()
            End Sub

            Public Overrides Sub SetLength(ByVal value As Long)
                ThrowIfDisposed()
                Throw New NotSupportedException()
            End Sub

            Public Overrides Sub Write(ByVal buffer As Byte(), ByVal offset As Integer, ByVal count As Integer)
                ThrowIfDisposed()
                Throw New NotSupportedException()
            End Sub
        End Class
    End Class
End Namespace
